#include "filedrawwidget.h"
#include<qdebug.h>
//文件读取相关
#include<QtXml/QDomDocument>
#include<QFile>
#include<QColor>

fileDrawWidget::fileDrawWidget(QWidget  *parent):
    QOpenGLWidget (parent)
{
    //变量初始化
    mouseStatus=NONE;
    offX=0;
    offY=0;
    preOffX=0;
    preOffY=0;
    scale=1;
    preScale=1;
    reset=false;
    isIndexSelected=false;
    indexGrid=new gridIndex();
    indexQuadTree=new quadTreeIndex();
}

fileDrawWidget::~fileDrawWidget()
{

}

//初始化
void fileDrawWidget::initializeGL()
{
    //m_context->makeCurrent(this);
    initializeOpenGLFunctions();//初始化OpenGL函数
    glClearColor(1.0,1.0,1.0,1.0);
    glClearDepth(1.0);
    getMinMax(&map);//获取坐标极值
    if(map.isProjected==false)
    {
        lambert=new projectionLambert(minY,maxY,minX,maxX);
        map.mapProjection(lambert);
        getProjMinMax(&map);
        gluOrtho2D(projMinX,projMaxX,projMinY,projMaxY);//设定正射投影范围，将范围内的坐标都转换成NDC
    }
    else
    {
        glOrtho(minX,maxX,minY,maxY,1,0);
    }


    glMatrixMode(GL_PROJECTION);//设定当前矩阵为投影矩阵
    glLoadIdentity();//用单位矩阵替换当前矩阵
    glGetDoublev(GL_PROJECTION_MATRIX,projectionMatrix);//保存此时的投影矩阵
    mapLoaded(&map);//发出信号调整窗口大小
}

//窗口尺寸变化响应
void fileDrawWidget::resizeGL(int w, int h)
{
    width=w;
    height=h;
    glViewport(0,0,width,height);//设置屏幕上的绘图区域，即将NDC映射为一定范围的屏幕坐标
}

//定义绘制内容
void fileDrawWidget::paintGL()
{
    if(mouseStatus==SCALE&&(preScale<scale||preScale>scale))//鼠标状态为缩放且缩放系数发生变化，否则会持续缩放
    {
        glTranslated(cursorPreLoc.rx(),cursorPreLoc.ry(),0);//将缩放中心点（坐标系原点移至当前鼠标位置）
        glScaled(scale,scale,0);
        glTranslated(-cursorPreLoc.rx(),-cursorPreLoc.ry(),0);//恢复坐标系原点
        preScale=scale;
    }
    if(mouseStatus==MOVE&&(preOffX>offX||preOffX<offX||preOffY>offY||preOffY<offY))//鼠标状态为平移且平移量发生变化，避免持续平移
    {
        glTranslated(offX,offY,0);
        preOffX=offX;
        preOffY=offY;
    }
    if(reset==true)
    {
        glLoadMatrixd(projectionMatrix);//复原矩阵
        reset=false;
    }

    openglRenderer.draw(&map);
    openglRenderer.drawIndex();
    if(mouseStatus==SELECT&&recSelectStart!=recSelectEnd) drawSelectRec();
}

//获取绘图文件的坐标极值
void fileDrawWidget::getMinMax(geoMap *map)
{
    for(auto &layer:map->geoLayers)
    {
        for(auto &object:layer->geoObjects)
        {
            if(object->type=="MultiLineString")
            {
                for(auto &line:dynamic_cast<geoMultiLineString *>(object)->lineStrings)
                {
                    for(auto &coordinate:line->coordinates)
                    {
                        if(coordinate.rx()>maxX)    maxX=coordinate.rx();
                        if(coordinate.rx()<minX)    minX=coordinate.rx();
                        if(coordinate.ry()>maxY)    maxY=coordinate.ry();
                        if(coordinate.ry()<minY)    minY=coordinate.ry();
                    }
                }
            }
            else if(object->type=="MultiPolygon")
            {
                for(auto &polygon:dynamic_cast<geoMultiPolygon *>(object)->polygons)
                {
                    for(auto &coordinate:polygon->coordinates)
                    {
                        if(coordinate.rx()>maxX)    maxX=coordinate.rx();
                        if(coordinate.rx()<minX)    minX=coordinate.rx();
                        if(coordinate.ry()>maxY)    maxY=coordinate.ry();
                        if(coordinate.ry()<minY)    minY=coordinate.ry();
                    }
                }
            }
            else
            {
                for(auto &coordinate:object->coordinates)
                {
                    if(coordinate.rx()>maxX)    maxX=coordinate.rx();
                    if(coordinate.rx()<minX)    minX=coordinate.rx();
                    if(coordinate.ry()>maxY)    maxY=coordinate.ry();
                    if(coordinate.ry()<minY)    minY=coordinate.ry();
                }
            }
        }
    }
}

//获取投影坐标极值
void fileDrawWidget::getProjMinMax(geoMap *map)
{
    for(auto &layer:map->geoLayers)
    {
        for(auto &object:layer->geoObjects)
        {
            if(object->type=="MultiLineString")
            {
                for(auto &line:dynamic_cast<geoMultiLineString *>(object)->lineStrings)
                {
                    for(auto &coordinate:line->projectedCoordinates)
                    {
                        if(coordinate.rx()>projMaxX)    projMaxX=coordinate.rx();
                        if(coordinate.rx()<projMinX)    projMinX=coordinate.rx();
                        if(coordinate.ry()>projMaxY)    projMaxY=coordinate.ry();
                        if(coordinate.ry()<projMinY)    projMinY=coordinate.ry();
                    }
                }
            }
            else if(object->type=="MultiPolygon")
            {
                for(auto &polygon:dynamic_cast<geoMultiPolygon *>(object)->polygons)
                {
                    for(auto &coordinate:polygon->projectedCoordinates)
                    {
                        if(coordinate.rx()>projMaxX)    projMaxX=coordinate.rx();
                        if(coordinate.rx()<projMinX)    projMinX=coordinate.rx();
                        if(coordinate.ry()>projMaxY)    projMaxY=coordinate.ry();
                        if(coordinate.ry()<projMinY)    projMinY=coordinate.ry();
                    }
                }
            }
            else
            {
                for(auto &coordinate:object->projectedCoordinates)
                {
                    if(coordinate.rx()>projMaxX)    projMaxX=coordinate.rx();
                    if(coordinate.rx()<projMinX)    projMinX=coordinate.rx();
                    if(coordinate.ry()>projMaxY)    projMaxY=coordinate.ry();
                    if(coordinate.ry()<projMinY)    projMinY=coordinate.ry();
                }
            }
        }
    }
}

//将屏幕坐标转换为OpenGL坐标
QPointF fileDrawWidget::screenToOpenGL(QPointF pt)
{
    GLdouble modelview[16]={0};
    GLint viewport[4]={0};
    glGetIntegerv(GL_VIEWPORT,viewport);
    glGetDoublev(GL_MODELVIEW_MATRIX, modelview);
    QPointF glPoint;
    double z1=0,z2=0;
    //将屏幕坐标转换为世界坐标
    gluUnProject(pt.rx(),pt.ry(),z1,modelview,projectionMatrix,viewport,&glPoint.rx(),&glPoint.ry(),&z2);
    glPoint.ry()=(glPoint.ry()+1)*(height+40)/2-1;
    glPoint.ry()=glPoint.ry()/height*2-1;
    return glPoint;
}


//鼠标响应事件
void fileDrawWidget::mousePressEvent(QMouseEvent *ev)
{
    cursorPreLoc=screenToOpenGL(QPointF(ev->x(),height-ev->y()));
    if(ev->button()==Qt::LeftButton&&mouseStatus==MOVE)
    {
        setCursor(Qt::ClosedHandCursor);//鼠标样式
    }
    if(mouseStatus==SELECT)
    {
        recSelectStart=openGLToProjected(cursorPreLoc);
        foreach(geoLayer*layer,map.geoLayers)
        {
            foreach(geoObject* object,layer->geoObjects)
            {
                if(object->isSelected==true)    object->isSelected=false;
            }
        }
    }
}

void fileDrawWidget::mouseMoveEvent(QMouseEvent *ev)
{
    QPointF pt=screenToOpenGL(QPointF(ev->x(),height-ev->y()));

    if(mouseStatus==MOVE&&(offX>ev->x()||offY>ev->y()||offX<ev->x()||offY<ev->y()))//鼠标状态正确且位置发生改变
    {
        offX=pt.rx()-cursorPreLoc.rx();
        offY=pt.ry()-cursorPreLoc.ry();
        update();
    }
    else if(mouseStatus==SELECT)//框选
    {
        recSelectEnd=openGLToProjected(pt);
        update();
    }
    cursorPreLoc=pt;
}

void fileDrawWidget::mouseReleaseEvent(QMouseEvent *ev)
{
    QPointF cursorCurrentLoc=screenToOpenGL(QPointF(ev->x(),height-ev->y()));
    recSelectEnd=openGLToProjected(cursorCurrentLoc);
    if(mouseStatus==SELECT&&recSelectStart==recSelectEnd)//点选
    {
        foreach(cellForIndex* cell,currentIndex->leafCells)
        {
            if(cell->isPointWithin(recSelectEnd))
            {
                QVector<geoObject*>objects=cell->getObjectWithin();
                foreach(geoObject* object,objects)
                {
                    foreach(geoPolygon* polygon,dynamic_cast<geoMultiPolygon*>(object)->polygons)
                    if(polygon->isPointWithin(recSelectEnd))
                        object->isSelected=true;
                }
            }
        }
        update();
    }
    if(mouseStatus==SELECT)
    {
        recSelectStart=QPointF(0,0);
        recSelectEnd=QPointF(0,0);//破坏画选择框的执行条件
        update();
    }
    cursorPreLoc=cursorCurrentLoc;
    if(ev->button()==Qt::LeftButton&&mouseStatus==MOVE)
    {
        setCursor(Qt::OpenHandCursor);
    }
}

void fileDrawWidget::drawSelectRec()
{
    glColor3d(0,0,0);
    glBegin(GL_LINE_LOOP);
        glVertex2d(recSelectStart.rx(),recSelectStart.ry());
        glVertex2d(recSelectStart.rx(),recSelectEnd.ry());
        glVertex2d(recSelectEnd.rx(),recSelectEnd.ry());
        glVertex2d(recSelectEnd.rx(),recSelectStart.ry());
    glEnd();
}

//滚轮事件
void fileDrawWidget::wheelEvent(QWheelEvent *ev)
{
    if(mouseStatus==SCALE)
    {
        QPoint angle=ev->angleDelta()/8;
        if(scale>0.32769&&scale<3.0517578124)//限制缩放程度
        {
            if(angle.ry()==15)  scale*=1.25;
            if(angle.ry()==-15) scale*=0.8;
            update();
        }
    }
    cursorPreLoc=screenToOpenGL(QPointF(ev->x(),height-ev->y()));
}

//复位
void fileDrawWidget::resetMap()
{
    offX=0;
    offY=0;
    scale=1;
    reset=true;
    update();
}

//调整窗口大小
double fileDrawWidget::getWidth()
{
    if(map.isProjected==false)
        return projMaxX-projMinX;
    else
        return maxX-minX;
}

double fileDrawWidget::getHeight()
{
    if(map.isProjected==false)
        return projMaxY-projMinY;
    else
        return maxY-minY;
}

void fileDrawWidget::readSLD(QString pathName)
{
    QDomDocument doc;
    QFile file(pathName);
    //打开文件失败
    if (!file.open(QIODevice::ReadOnly))
        return;
    if (!doc.setContent(&file)) {
        file.close();
        return;
    }
    file.close();

    QDomElement styledLayerDescriptor=doc.documentElement();//根节点
    QDomNode node=styledLayerDescriptor.firstChild();//NamedLayer
    node=node.lastChild();//UserStyle
    node=node.lastChild();//se:FeatureTypeStyle
    QDomNode rule=node.firstChild();
    while(!rule.isNull())
    {
        for(auto &object:map.geoLayers[0]->geoObjects)
        {
            QDomElement name=rule.firstChild().toElement();
            if(object->name==name.text())
            {
                QDomNode polygonSymbolizer=rule.lastChild();
                QDomNode fill=polygonSymbolizer.firstChild();
                QDomElement fillColor=fill.firstChild().toElement();//面填充色
                object->renderStyle.fillColor=fillColor.text();
                QDomNode stroke=polygonSymbolizer.lastChild();
                QDomElement lineColor=stroke.firstChild().toElement();//线色
                object->renderStyle.lineColor=lineColor.text();
                QDomElement lineWidth=lineColor.nextSibling().toElement();//线宽
                object->renderStyle.lineWidth=lineWidth.text().toFloat();
            }
            object->isRendered=true;
        }
        rule=rule.nextSibling();
    }
    update();
}

//索引
bool fileDrawWidget::setCurrentIndex(spatialIndex* index)
{
    if(index==nullptr)
    {
        qDebug()<<"当前索引为空。";
        return false;
    }
    openglRenderer.setPaintIndex(index);
    currentIndex=index;
    isIndexSelected=true;
    update();
    return true;
}

gridIndex* fileDrawWidget::getGridIndex()
{
    return this->indexGrid;
}

quadTreeIndex* fileDrawWidget::getQuadTreeIndex()
{
    return this->indexQuadTree;
}

QPointF fileDrawWidget::openGLToProjected(QPointF pt)
{
    QPointF projectedPt;
    double distX,distY;
    if(map.isProjected==false)
    {
        distX=projMaxX-projMinX;
        distY=projMaxY-projMinY;
        projectedPt.rx()=projMinX+(pt.x()+1)*distX/2;
        projectedPt.ry()=projMinY+(pt.y()+1)*distY/2;
    }
    else
    {
        distX=maxX-minX;
        distY=maxY-minY;
        projectedPt.rx()=minX+(pt.x()+1)*distX/2;
        projectedPt.ry()=minY+(pt.y()+1)*distY/2;
    }
    return projectedPt;
}
